/**
 * @Author       : Mo 2427995270@qq.com
 * @Date         : 2024-04-28 11:47:01
 * @LastEditTime : 2025-05-29 14:25:41
 * @FilePath     : \KT-02CS-APP\libs\mo_database.c
 * @Description  : 数据库
 * @Version      : V1.0
 * @History      :
 * @Note         :
 */
/***************************************Includes***********************************/
#include "mo_database.h"
#include "fatfs/ff.h"

#include <stdint.h>
#include <string.h>
#include <time.h>

/************************************Private Macros********************************/
#define DB_INFO_SIZE 1024
#define DATA_INFO_SIZE

enum MO_DATA_STATUS { MO_DATA_STATUS_INVALID,
                      MO_DATA_STATUS_VALID };

/**********************************Private Statement*******************************/

typedef struct {
    uint32_t size;
    uint32_t time;
    uint32_t flag;
} mo_data_info_t;

/***********************************Public Variables*******************************/



/**********************************Private Variables*******************************/

static mo_db_info_t db_info_def = {
    .ver = MO_DB_VER,
    .quantity = 0,
    .sn_max = 0,
    .sector_size = 0,
};

/**********************************Public Functions********************************/

/**
 * @brief 打开数据库
 * @param  db
 * @param  db_path          数据库路径
 * @param  sector_size      扇区大小 仅创建数据库时有效
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_open(mo_db_t *db, const char *db_path, int sector_size) {
    UINT br = 0;
    if (db->fd.obj.fs != NULL)
        return -1;
    if (db_path && (db->db_path != db_path))
        strncpy(db->db_path, db_path, sizeof(db->db_path));

    FRESULT ret = f_open(&db->fd, db->db_path, FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
    if (ret != FR_OK)
        return -1;
    ret = f_read(&db->fd, &db->info, sizeof(db->info), &br);
    if (ret != FR_OK)
        return -1;
    if (br == 0) {
        db_info_def.sector_size = sector_size;
        f_lseek(&db->fd, 0);
        ret = f_write(&db->fd, &db_info_def, sizeof(db_info_def), &br);
        if (ret != FR_OK || br != sizeof(db_info_def))
            return -1;
        f_sync(&db->fd);
        db->info = db_info_def;
    }

    // f_close(&db->fd);
    return 0;
}
/**
 * @brief 关闭数据库
 * @param  db               
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_close(mo_db_t *db) {
    if (f_close(&db->fd) != FR_OK)
        return -1;
    return 0;
}
/**
 * @brief 重启数据库
 * @param  db               
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_reboot(mo_db_t *db) {
    mo_db_close(db);
    return mo_db_open(db, db->db_path, db->info.sector_size);
}

/**
 * @brief 写入或修改数据
 * @param  db
 * @param  sn               序号起始1
 * @param  t                修改时间
 * @param  buf              待写入的数据
 * @param  size             数据长度
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_write(mo_db_t *db, int sn, time_t t, const void *buf, int size) {
    if ((db->fd.obj.fs == NULL) || (sn <= 0) || (size > db->info.sector_size - sizeof(mo_data_info_t)))
        return -1;
    UINT br = 0;
    int add = 0;
    FRESULT ret = f_lseek(&db->fd, DB_INFO_SIZE + (sn - 1) * db->info.sector_size);
    if (ret != FR_OK)
        return -1;
    mo_data_info_t data_info;
    memset(&data_info, 0, sizeof(data_info));
    // 读取数据信息
    ret = f_read(&db->fd, &data_info, sizeof(data_info), &br);
    if (ret != FR_OK)
        return -1;
    // 数据信息不存在或数据为无效状态
    if (br != sizeof(data_info) || data_info.flag == MO_DATA_STATUS_INVALID) {
        db->info.quantity++;
        add = 1;
    }
    ret = f_lseek(&db->fd, DB_INFO_SIZE + (sn - 1) * db->info.sector_size);
    if (ret != FR_OK) {
        if (add)
            db->info.quantity--;
        return -1;
    }

    data_info.size = size;
    data_info.time = t;
    data_info.flag = MO_DATA_STATUS_VALID;
    ret = f_write(&db->fd, &data_info, sizeof(data_info), &br);
    if (ret != FR_OK || br != sizeof(data_info)) {
        if (add)
            db->info.quantity--;
        return -1;
    }
    ret = f_write(&db->fd, buf, size, &br);
    if (ret != FR_OK || br != size) {
        if (add)
            db->info.quantity--;
        return -1;
    }
    // 不是新增数据，是修改数据
    if (add == 0)
        return 0;

    ret = f_lseek(&db->fd, 0);
    if (ret != FR_OK)
        return -1;
    if (sn > db->info.sn_max)
        db->info.sn_max = sn;
    if (db->info.time_earliest == 0 || db->info.time_earliest > t)
        db->info.time_earliest = t;
    if (db->info.time_latest < t)
        db->info.time_latest = t;
    ret = f_write(&db->fd, &db->info, sizeof(db->info), &br);
    if (ret != FR_OK)
        return -1;
    f_sync(&db->fd);
    return 0;
}
/**
 * @brief 根据序号读取数据
 * @param  db
 * @param  sn               序号起始1
 * @param  buf              存储待读取数据
 * @param  size             buf大小
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_read_sn(mo_db_t *db, int sn, void *buf, int size) {
    if ((db->fd.obj.fs == NULL) || (sn <= 0) || (size > db->info.sector_size - sizeof(mo_data_info_t)))
        return -1;
    UINT br = 0;
    FRESULT ret = f_lseek(&db->fd, DB_INFO_SIZE + (sn - 1) * db->info.sector_size);
    if (ret != FR_OK)
        return -1;
    mo_data_info_t data_info;
    memset(&data_info, 0, sizeof(data_info));
    ret = f_read(&db->fd, &data_info, sizeof(data_info), &br);
    if (ret != FR_OK)
        return -1;
    if (br != sizeof(data_info) || data_info.flag == MO_DATA_STATUS_INVALID) {
        return -1;
    }
    ret = f_read(&db->fd, buf, size, &br);
    if (ret != FR_OK || br == 0)
        return -1;

    return 0;
}
/**
 * @brief 根据开始和结束时间读取数据
 * @param  db
 * @param  time_s
 * @param  time_e
 * @param  offset           查询偏移量(跳过的数据量)
 * @param  reverse          0正序 1倒序
 * @param  buf              存储数据的缓冲区，cb为NULL时该参数无效
 * @param  size             要读数据的大小，一条的，cb为NULL时该参数无效
 * @param  usr_data         用户数据
 * @param  cb               接收数据的回调，给NULL可查询时间段的数据量, cb返回负数可中断查询
 * @return int 数据量 -1失败
 * @note null
 */
int mo_db_read_date(mo_db_t *db, time_t time_s, time_t time_e, int offset, int reverse, void *buf, int size, void *usr_data, mo_db_cb_t cb) {
    if ((db->fd.obj.fs == NULL) || (size < 0))
        return -1;
    if (cb && !buf)
        return -1;
    if (time_e < time_s) {
        time_t tmp = time_e;
        time_e = time_s;
        time_s = tmp;
    }
    UINT br = 0;
    FRESULT ret = 0;
    int num = 0;
    mo_data_info_t data_info;
    memset(&data_info, 0, sizeof(data_info));

    // 逆序查询
    if (reverse > 0) {
        for (size_t i = db->info.sn_max; i >= 1; i++) {
            ret = f_lseek(&db->fd, DB_INFO_SIZE + (i - 1) * db->info.sector_size);
            if (ret != FR_OK)
                continue;
            ret = f_read(&db->fd, &data_info, sizeof(data_info), &br);
            if (ret != FR_OK || br != sizeof(data_info))
                continue;
            // 数据已删除或不在指定的时间段内
            if (data_info.flag != MO_DATA_STATUS_VALID || (data_info.time < time_s || data_info.time > time_e))
                continue;
            if (!cb) {
                num++;
                continue;
            }
            num++;
            // 跳过偏移量的数据
            if(num <= offset) {
                continue;
            }
            ret = f_read(&db->fd, buf, size, &br);
            if (ret != FR_OK || br == 0)
                continue;
            
            if (cb(buf, br, num, usr_data) < 0)
                break;
        }
    } else {
        for (size_t i = 1; i <= db->info.sn_max; i++) {
            ret = f_lseek(&db->fd, DB_INFO_SIZE + (i - 1) * db->info.sector_size);
            if (ret != FR_OK)
                continue;
            ret = f_read(&db->fd, &data_info, sizeof(data_info), &br);
            if (ret != FR_OK || br != sizeof(data_info))
                continue;
            // 数据已删除或不在指定的时间段内
            if (data_info.flag != MO_DATA_STATUS_VALID || (data_info.time < time_s || data_info.time > time_e))
                continue;
            if (!cb) {
                num++;
                continue;
            }
            num++;
            if(num <= offset) {
                continue;
            }
            ret = f_read(&db->fd, buf, size, &br);
            if (ret != FR_OK || br == 0)
                continue;
            
            if (cb(buf, br, num, usr_data) < 0)
                break;
        }
    }

    return num;
}

/**
 * @brief 删除数据
 * @param  db
 * @param  sn
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_remove(mo_db_t *db, int sn) {
    if ((db->fd.obj.fs == NULL) || (sn <= 0))
        return -1;
    UINT br = 0;
    int add = 0;
    FRESULT ret = f_lseek(&db->fd, DB_INFO_SIZE + (sn - 1) * db->info.sector_size);
    if (ret != FR_OK)
        return -1;
    mo_data_info_t data_info;
    memset(&data_info, 0, sizeof(data_info));
    ret = f_read(&db->fd, &data_info, sizeof(data_info), &br);
    if (ret != FR_OK)
        return -1;
    if (data_info.flag == MO_DATA_STATUS_INVALID) {
        return 0;
    }

    ret = f_lseek(&db->fd, DB_INFO_SIZE + (sn - 1) * db->info.sector_size);
    if (ret != FR_OK)
        return -1;

    data_info.flag = MO_DATA_STATUS_INVALID;
    ret = f_write(&db->fd, &data_info, sizeof(data_info), &br);
    if (ret != FR_OK || br != sizeof(data_info)) {
        return -1;
    }
    ret = f_lseek(&db->fd, 0);
    if (ret != FR_OK)
        return -1;
    db->info.quantity--;
    ret = f_write(&db->fd, &db->info, sizeof(db->info), &br);
    if (ret != FR_OK)
        return -1;
    return 0;
}
/**
 * @brief 删除所有数据
 * @param  db
 * @return int 0成功 -1失败
 * @note null
 */
int mo_db_clear(mo_db_t *db) {
    int ret = 0;
    // for (size_t i = db->info.quantity; i > 0; i--) {
    // 	ret = mo_db_remove(db, i);
    // 	if(ret < 0)
    // 		return -1;
    // }

    f_close(&db->fd);
    ret = f_unlink(db->db_path);
    mo_db_open(db, NULL, db->info.sector_size);

    return 0;
}
/**********************************Private Functions*******************************/


/* [] END OF FILE */
